# _*_ coding:utf-8 _*_
# @Time  : 2023.08.21
# @Author: zizlee
import re
import pathlib
import requests
import datetime
import json
import time
import threading
from fastapi import FastAPI, Body, Query
from urllib3 import disable_warnings
from queue import Queue

disable_warnings()

app = FastAPI()


class RobotUtils(object):

    def __init__(self):
        self.file_local_folder = ''
        self.hook_users = {}
        self.file_type = {}
        self.file_info = {}
        self.variety_info = {}
        self.server_urls = {}
        self.email_sender = {}
        self.email_receivers = {}
        self.load_configs()

    def load_configs(self):
        with open('configs.json', 'r', encoding='utf8') as cfg:
            config = json.load(cfg)
        self.file_local_folder = config['localFileFolder']
        self.hook_users = config['HookUsers']
        self.file_type = config['fileType']
        self.file_info = config['fileInfo']
        self.variety_info = config['varietyInfo']
        self.server_urls = config['serverUrl']
        self.email_sender = config['emailSender']
        self.email_receivers = config['emailReceivers']

    def get_email_sender(self):
        return self.email_sender

    def get_email_receivers(self):
        return self.email_receivers

    def get_email_local_file_folder(self):
        return self.email_sender.get('localFolder')

    # 使用文件名解析出邮件标题名称
    def get_email_file_customer_name(self, filename, file_date):
        # 先从filename解析到品种代码，再从品种代码解析到商品期货还是金融期货和文件作者
        customer_filename = ''
        variety_en = self.get_variety_en(filename)
        if variety_en:
            for vk, vv in self.variety_info.items():
                if vk == variety_en:
                    author = vv.get('mail_author')
                    if author:
                        customer_filename = f'瑞达期货*商品期货*{filename.replace(".pdf", "")}*{author}{file_date}'
                    break
        return customer_filename

    def in_hook_users(self, wx_id):
        return self.hook_users.get(wx_id)

    def get_local_file_folder(self):
        return self.file_local_folder

    def get_save_url(self, save_type):
        return self.server_urls.get(save_type)

    def get_author_wx_id(self, filename: str):
        variety_en = self.get_variety_en(filename)
        if not variety_en:
            return None
        wx_id = None
        v_info = self.variety_info.get(variety_en)
        if v_info:
            wx_id = v_info['sender']
        return wx_id

    def get_author_id(self, variety_en=None, wx_id=None):
        aid = None
        if variety_en:
            v_info = self.variety_info.get(variety_en)
            if v_info:
                aid = v_info['sender_id']
        if wx_id:
            for vk, vv in self.variety_info.items():
                if vv['sender'] == wx_id:
                    aid = vv['sender_id']
                    break
        return aid

    def get_file_type(self, filename: str):
        file_type = None
        for f_key, t_obj in self.file_type.items():
            if filename.find(f_key) > -1:
                file_type = t_obj['type_flag']
                break
        return file_type

    def get_variety_en(self, filename: str):
        variety_en = None
        for v_name, v_obj in self.file_info.items():
            if filename.find(v_name) > -1:
                variety_en = v_obj['code']
                break
        return variety_en


"""
# 收到消息
{
    "type": 100, // 推送类型，固定为100
    "msg_type": 1, // 消息类型
    "local_id": "1381", // 本地消息ID
    "msg_id": "3921711251800000000", // 消息ID【自己发送的消息时为0】
    "wx_id": "wxid_xxxx", // 微信ID,
    "at_list": ["wxid_xxx1", "wxid_xxx2"], // 群消息艾特人列表，艾特所有人就是【notify@all】
    "content": "你好鸭", // 消息内容
    "sender": "wxid_xxxx", // 如果是群消息，该参数为发送者的微信ID，否则为空
    "file_path": "E:\\微信缓存\\WeChat Files\\xxxxx", // 消息文件路径
    "time_stamp": 1682944354, // 发送时间
    "is_self_msg": 1, // 是否是自己发送的消息 0:别人发来的 1:自己发的
    "is_pc_msg": 1, // 是否是PC端发送的消息(仅用于判断自己发送的消息，别人发送的都是0) 0:否 1:是
    "self_wx_id": "wxid_xxxx", // 自己的微信ID
    "port": 8989 // DLL的端口号
}
# 撤回消息
{
    "type": 666, // 推送类型，固定为666
    "msg_type": 1, // 消息类型
    "is_self_revoke": 1, // 是否是自己撤回的 0否 1是
    "time_stamp": 1682944354, // 发送时间【注意！是发送时间，不是撤回时间】
    "wx_id": "wxid_xxxx", // 微信ID/群ID
    "content": "你好鸭", // 消息内容
    "member_wx_id": "wxid_xxxx", // 如果是群里的撤回消息，该参数为群成员的微信ID，否则为空
    "self_wx_id": "wxid_xxxx", // 自己的微信ID
    "port": 8989 // DLL的端口号
}
"""


msg_queue = Queue()


def save_short_message(msg, robot_util):
    if not re.match(r"《.*》", msg['content'][:6]):
        print('不是目标短讯通数据，舍弃！')
        return 0  # 不是需要的数据，返回
    content = msg['content']
    if content[-6:] == "（瑞达研究）" or content[-6:] == '(瑞达研究)':
        content = content[:-6]
    author_id = robot_util.get_author_id(wx_id=msg['sender'])
    if not author_id:
        print('微信ID={}的系统id不存在！'.format(msg['sender']), 'error')
        return 0  # 有些不重要的人重复发，也不懂咋回事。作者没维护好的就不要了
    save_url = robot_util.get_save_url(save_type='SHORTMSG')
    try:
        create_time = datetime.datetime.fromtimestamp(msg['time_stamp']).strftime('%Y-%m-%d %H:%M:%S')
        r1 = requests.post(save_url, json={'create_time': create_time, 'author_id' :author_id, 'content': content}, verify=False)
        r1.json()  # 保存到工作系统
        save_url2 = robot_util.get_save_url(save_type='RUIZHI_SHORTMSG')
        create_time = datetime.datetime.fromtimestamp(msg['time_stamp']).strftime('%Y-%m-%d %H:%M:%S')
        r2 = requests.post(save_url2, json={'msg_time': create_time, 'msg_type': 1, 'content': content}, verify=False)
        r2.json()  # 同时保存到瑞智系统
    except Exception as e:
        print('保存短信息出错了: {}'.format(e), 'error')
        return 1
    else:
        print('保存短信息完成，队列剩余:{}'.format(msg_queue.qsize()))
        return 0


def save_file_message(msg, robot_util):
    if int(time.time()) - msg['time_stamp'] <= 300:  # 5min
        return 1
    local_filepath = pathlib.Path(msg['file_path'])
    if not local_filepath.exists():
        print('文件：{} 不存在，可能为撤回消息，舍弃！'.format(local_filepath.name))
        return 0  # 文件不存在，可能是对方已经撤回了
    file_type = robot_util.get_file_type(local_filepath.name)
    if not file_type:
        print('文件名：{} 寻找文件类型不存在，舍弃！'.format(local_filepath.name), 'info')
        return 0  # 可能不是需要的文件
    variety_en = robot_util.get_variety_en(local_filepath.name)
    if not variety_en:
        print('文件名：{} 寻找品种代码不存在，舍弃！'.format(local_filepath.name), 'info')
        return 0  # 可能不是需要的文件
    if file_type == 'WEEKLY' and variety_en == 'RJILR':
        variety_en = 'RDCCS'  # 周报的名称为谷物类的实际是玉米系
    author_id = robot_util.get_author_id(variety_en=variety_en)
    if not author_id:
        print('微信ID={}的系统id不存在！'.format(msg['sender']), 'error')
        return 1  # 作者没有维护好，需添加
    save_url = robot_util.get_save_url(save_type=file_type)
    if not save_url:
        print('文件名：{} ，没找到保存路径，不需要的文件类型，舍弃！'.format(local_filepath.name))
        return 0  # 还未支持自动上传的文件类型
    file = open(local_filepath, 'rb')
    try:
        file_date = datetime.datetime.fromtimestamp(msg['time_stamp']).strftime('%Y%m%d')
        r = requests.post(save_url, files={'file': file}, data={'author_id': author_id, 'variety_en': variety_en, 'file_date': file_date}, verify=False)
        resp = r.json()
        file.close()
        # 上传报告到瑞智系统，只需上传信息，后端自动查询报告所在路径入库。（故需要在以上上传之后执行）
        ruizhi_url = 'http://210.13.218.130:9001/v1/admin/dailymaintain/periodReport/create/'
        file_date2 = datetime.datetime.fromtimestamp(msg['time_stamp']).strftime('%Y-%m-%d')
        file_title = local_filepath.name.replace(local_filepath.suffix, '')
        for i in range(1, 10):
            file_title = file_title.replace(f'({i})', '').replace(f'（{i}）', '')
            if file_title.find('(') == -1 and file_title.find('（') == -1:
                break
        r2 = requests.post(ruizhi_url, json=[{'file_date': file_date2, 'variety_en': variety_en, 'title': file_title, 'file_type': file_type, 'filepath': ''}])
        print('上传瑞智系统:', r2.json())
    except Exception as e:
        print('上传报告出错了: {}'.format(e), 'error')
        return 0
    else:
        print('{}，队列剩余：{}'.format(resp.get('msg'), msg_queue.qsize()), 'success')
        if resp['code'] in [200, 299]:
            return 0
        else:
            print('上传文件错误:{}'.format(resp['msg']), 'error')
            return 1


def handle_message_thread():
    robot_utils = RobotUtils()
    robot_utils.load_configs()
    while True:
        msg = msg_queue.get(block=True)
        if msg['msg_type'] == 1:  # 文字消息
            save_ret = save_short_message(msg, robot_util=robot_utils)
        elif msg['msg_type'] == 49:  # 文件消息
            save_ret = save_file_message(msg, robot_util=robot_utils)
        else:
            save_ret = 0
        if save_ret == 1:
            msg_queue.put(msg)  # 丢回队列继续处理
        time.sleep(1)


@app.on_event("startup")
async def startup_event():
    t = threading.Thread(target=handle_message_thread)
    t.setDaemon(True)
    t.start()


@app.post("/msg")
def read_root(body: dict = Body(...)):
    print(f'{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}收到消息。')
    if not body['wx_id'].startswith('gh_'):
        now_date = datetime.datetime.now().strftime('%Y-%m-%d')
        log_folder = pathlib.Path('msgLog').joinpath(now_date)
        if not log_folder.exists():
            log_folder.mkdir(parents=True)
        log_file = log_folder.joinpath(f'{datetime.datetime.now().strftime("%H_%M_%S")}.log')
        with open(log_file, 'w', encoding='utf8') as lg:
            json.dump(body, lg, indent=2, ensure_ascii=False)

    if body['wx_id'] in ['7871417960@chatroom', '48360866895@chatroom']:  # 业务部门对接平台
        if body['wx_id'].endswith('@chatroom'):
            sender = body['sender']
            msg_room = body['wx_id']
        else:
            sender = body['wx_id']
            msg_room = ''
        file_path = body['file_path']
        if body['msg_type'] == 1:  # 文字消息
            file_path = ''
        msg_queue.put({
            'type': body['type'],
            'time_stamp': body['time_stamp'],  # 发送时间
            'msg_type': body['msg_type'],  # 消息类型
            'msg_room': msg_room,  # 群ID,
            'sender': sender,
            'content': body['content'],
            'file_path': file_path
        })
    return {'success': True}


@app.get("/readLocalPeriodReport")
def read_local_period_report_file(wx: bool = Query(False), hand_date: str = Query(None)):
    config_utils = RobotUtils()
    config_utils.load_configs()
    file_date = datetime.datetime.today()
    if hand_date:
        file_date = datetime.datetime.strptime(hand_date, '%Y-%m-%d')
    current_month = file_date.strftime('%Y-%m')
    if wx:
        file_folder = pathlib.Path(config_utils.get_local_file_folder()).joinpath('wxid_ebc8cjnovw1f22').joinpath('FileStorage/File').joinpath(current_month)
    else:
        file_folder = pathlib.Path('C:/Users/Administrator/Desktop/wxrobot/localFile')
    if not file_folder.exists():
        return {'success': True, 'message': '文件夹不存在:{}'.format(file_folder)}
    # 读取文件，解析信息，放入队列
    find_date_string = file_date.strftime('%Y%m%d')
    for pdf_file in file_folder.glob('*.pdf'):
        # 获取文件名称上就有该日期的或者创建日期是该日期的
        file_stamp_time = pdf_file.stat().st_ctime
        if pdf_file.name.find(find_date_string) < 0 and datetime.date.fromtimestamp(file_stamp_time) != file_date:
            print('pass:', pdf_file.name)
            continue
        # if pdf_file.name.find('周报') >= 0:
        #     continue
        sender_wx_id = config_utils.get_author_wx_id(pdf_file.name)
        if not sender_wx_id:
            print('文件名: {} 没有找到微信ID,跳过!'.format(pdf_file.name))
            continue
        msg_queue.put({
            'type': 100,
            'time_stamp': int(file_stamp_time) - 290,
            'msg_type': 49,
            'msg_room': '',
            'content': '',
            'sender': sender_wx_id,
            'file_path': str(pdf_file),
        })
        print('成功读取文件：{}'.format(pdf_file.name), file_stamp_time, datetime.datetime.fromtimestamp(file_stamp_time - 290))
        time.sleep(0.5)
    return {'success': True, 'message': '读取文件到队列完成，未处理消息{}个。'.format(msg_queue.qsize()), 'file_folder': str(file_folder)}
